package cn.byapps.hw.schedule;

import cn.byapps.hw.dao.CronDao;
import cn.byapps.hw.dao.HomeworkFileDao;
import cn.byapps.hw.dao.HomeworkRequirementDao;
import cn.byapps.hw.entity.Cron;
import cn.byapps.hw.entity.HomeworkFile;
import cn.byapps.hw.vo.ItemVO;
import com.qiniu.common.QiniuException;
import com.qiniu.http.Response;
import com.qiniu.storage.BucketManager;
import com.qiniu.storage.Configuration;
import com.qiniu.storage.Region;
import com.qiniu.storage.model.BatchStatus;
import com.qiniu.storage.model.FileInfo;
import com.qiniu.util.Auth;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.TriggerContext;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.transaction.Transactional;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Optional;

@Component
@Transactional
public class TaskDeleteOldFile implements SchedulingConfigurer {

    @Value("${accessKey}")
    private String accessKey;// = "0o2MS26kFvP0vQPXIyk8TXdo6sIS1l3PRwES4Gwz";
    @Value("${secretKey}")
    private String secretKey;// = "WzafRljF_f_FEvv5TI_LaC7xTlbge9gPJTWQhrfW";
    @Value("${downloadPath}")
    private String downloadPath;
    @Value("${upload}")
    private String upload;
    @Value("${bucket}")
    private String bucket;// = "byapps";

    @Resource
    private HomeworkFileDao homeworkFileDao;
    @Resource
    private HomeworkRequirementDao homeworkRequirementDao;
    @Resource
    private CronDao cronDao;

    public static String cron;

    public void deleteOldFile() {
        // 1.先从数据库获取过时文件
        Date now = new Date();
        // SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        List<HomeworkFile> homeworkFiles = homeworkFileDao.findAll();
        List<HomeworkFile> oldFile = new ArrayList<>();
        for (HomeworkFile h : homeworkFiles) {
            Date data = h.getFileDate();
            long betweenDate = (now.getTime() - data.getTime()) / (60 * 60 * 24 * 1000);
            if (betweenDate > 365)
                oldFile.add(h);
        }
        // 2.从七牛云获取所有文件
        Configuration cfg = new Configuration(Region.huanan());
        Auth auth = Auth.create(accessKey, secretKey);
        BucketManager bucketManager = new BucketManager(auth, cfg);
        // 文件名前缀
        String prefix = "";
        // 每次迭代的长度限制，最大1000，推荐值 1000
        int limit = 1000;
        // 指定目录分隔符，列出所有公共前缀（模拟列出目录效果）。缺省值为空字符串
        String delimiter = "";
        // 列举空间文件列表
        BucketManager.FileListIterator fileListIterator = bucketManager.createFileListIterator(bucket, prefix, limit,
                delimiter);

        List<ItemVO> list = new ArrayList<>();
        while (fileListIterator.hasNext()) {
            // 处理获取的file list结果
            FileInfo[] items = fileListIterator.next();
            // String dateStr = Long.toString(System.currentTimeMillis() / 1000L);
            for (FileInfo item : items)
                list.add(new ItemVO(item.key, item.hash, item.fsize, item.mimeType,
                        Long.parseLong((item.putTime + "").substring(0, 10)), item.endUser));
        }

        // 3.获取要删除的文件的Key值
        List<ItemVO> deletList = new ArrayList<>();
        List<HomeworkFile> hf = new ArrayList<>();

        for (HomeworkFile f : oldFile)
            for (ItemVO i : list)
                if (i.getKey().equals(f.getFilePath().substring(23))) {
                    deletList.add(i);
                    hf.add(f);
                }
        String[] keyList;
        // 因为单次删除文件不能超1000
        if (deletList.size() > 1000)
            keyList = new String[1000];
        else
            keyList = new String[deletList.size()];

        for (int i = 0; i < deletList.size(); i++)
            keyList[i] = deletList.get(i).getKey();

        System.out.println(deletList.size());

        if (deletList.size() == 0) {
            System.out.println("没有过时文件");
            return;
        }

        // 4.删除文件
        try {
            // 单次批量请求的文件数量不得超过1000
            BucketManager.BatchOperations batchOperations = new BucketManager.BatchOperations();
            batchOperations.addDeleteOp(bucket, keyList);
            Response response = bucketManager.batch(batchOperations);
            BatchStatus[] batchStatusList = response.jsonToObject(BatchStatus[].class);
            for (int i = 0; i < keyList.length; i++) {
                BatchStatus status = batchStatusList[i];
                String key = keyList[i];
                System.out.print(key + "\t");
                if (status.code == 200) {
                    System.out.println("删除成功");
                    homeworkFileDao.delete(hf.get(i));
                } else {
                    System.out.println(status.data.error);
                }
            }
        } catch (QiniuException ex) {
            System.err.println(ex.response.toString());
        }
        // 使用递归继续删除过时文件
        if (deletList.size() > 1000)
            deleteOldFile();
    }

    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        // 项目部署时，会在这里执行一次，从数据库拿到cron表达式
        Optional<Cron> optionalCron = cronDao.findById(2);
        if (optionalCron != null && optionalCron.isPresent()) {
            cron = cronDao.findById(1).get().getCron();
        } else {
            cron = "0 0 6 * * ?";
            cronDao.saveAndFlush(new Cron(2, "0 0 6 * * ?"));
        }

        Runnable task = new Runnable() {
            @Override
            public void run() {
                // 任务逻辑代码部分.
                System.out.println(cron);
                deleteOldFile();
            }
        };
        Trigger trigger = new Trigger() {
            @Override
            public Date nextExecutionTime(TriggerContext triggerContext) {
                // 任务触发，可修改任务的执行周期.
                // 每一次任务触发，都会执行这里的方法一次，重新获取下一次的执行时间
                if (optionalCron != null && optionalCron.isPresent()) {
                    cron = cronDao.findById(1).get().getCron();
                } else {
                    cron = "0 0 6 * * ?";
                    cronDao.saveAndFlush(new Cron(2, "0 0 6 * * ?"));
                }
                CronTrigger trigger = new CronTrigger(cron);
                Date nextExec = trigger.nextExecutionTime(triggerContext);
                return nextExec;
            }
        };
        taskRegistrar.addTriggerTask(task, trigger);
    }
}